package com.homestead.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.homestead.annotation.MethodAroundLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author yhb
 * @date 2021-03-10 10:40
 */
@Aspect
@Component
public class MyMethodLogAspect {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private static final String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    @Pointcut(value = "@annotation(com.homestead.annotation.MethodAroundLog)")
    private void pointcutForMethodAroundLog() {}

    @Pointcut(value = "@annotation(com.homestead.annotation.MethodBeforeLog)")
    private void pointcutForMethodBeforeLog() {}

    @Before(value = "pointcutForMethodBeforeLog()")
    public void beforeForMethodLog(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        MethodAroundLog methodAnnotation = method.getAnnotation(MethodAroundLog.class);
        // 忽略则不打日志
        if (methodAnnotation.ignore()) {
            return;
        }

        Class<?> declaringClass = method.getDeclaringClass();

        String markMethodStr = declaringClass.getName() + "#@#" + method.getName();

        String argsStr = JSON.toJSONStringWithDateFormat(joinPoint.getArgs(), NORM_DATETIME_PATTERN, SerializerFeature.WriteMapNullValue);
        logger.info("methodBeforeLog, {} start, 入参：{}", markMethodStr, argsStr);
    }


    @Around(value = "pointcutForMethodAroundLog()")
    public Object aroundForMethodLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        MethodAroundLog methodAnnotation = method.getAnnotation(MethodAroundLog.class);
        // 忽略则不打日志
        if (methodAnnotation.ignore()) {
            return joinPoint.proceed();
        }

        Class<?> declaringClass = method.getDeclaringClass();

        String markMethodStr = declaringClass.getName() + "#" + method.getName();

        String argsStr = JSON.toJSONStringWithDateFormat(joinPoint.getArgs(), NORM_DATETIME_PATTERN, SerializerFeature.WriteMapNullValue);
        logger.info("methodAroundLog, {} start, 入参：{}", markMethodStr, argsStr);

        long time = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        time = System.currentTimeMillis() - time;

        String resultStr = JSON.toJSONStringWithDateFormat(result, NORM_DATETIME_PATTERN, SerializerFeature.WriteMapNullValue);
        logger.info("methodAroundLog, {} end，耗时{}ms,出参：{}", markMethodStr, time, resultStr);
        return result;
    }

    @AfterThrowing(pointcut = "pointcutForMethodAroundLog()", throwing = "e")
    public void afterThrowingForMethodLog(JoinPoint joinPoint, Exception e) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        MethodAroundLog methodAnnotation = method.getAnnotation(MethodAroundLog.class);

        if (!methodAnnotation.ignore()) {
            Class<?> declaringClass = method.getDeclaringClass();
            String markMethodStr = declaringClass.getName() + "#" + method.getName();
            logger.info("methodAroundLog, {} afterThrowing，eMessage={}", markMethodStr, e.getMessage());
        }
    }
}
